package webmail;

import java.net.Socket;
import java.net.ServerSocket;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.io.*;
import java.util.*;
import javax.swing.Timer;

public class Main {

    static Socket webmailClientSocket = null;
    static ServerSocket webmailServerSocket = null;
    static PrintWriter out = null;
    static BufferedReader in = null;
    static EmailMessage[] messages = new EmailMessage[30];
    static Timer[] timers = new Timer[30];
    static int messageCounter = 0;  //automatically decremented when a message is sent

    public static void main(String[] args) throws IOException {

        OpenServerSocket();
        while (true)
        {
            try
            {
                //Accept a client connection
                ConnectToClientSocket();
                //Capture the HTTP header and request
                String[] httpRequest = GetHttpRequest();
                //Check what kind of request we have
                switch (HttpHeaderType(httpRequest))
                {
                    case 1:
                    {
                        ShowInputPage();
                        break;
                    }
                    case 2:
                    {
                        messageCounter += 1;
                        messages[messageCounter] = new EmailMessage(httpRequest[httpRequest.length-1]);
                        if (messages[messageCounter].delay == 0)
                        {
                            messages[messageCounter].SendMessage();
                            ReturnPage("Message sent successfully!");
                        }
                        else
                        {
                            timers[messageCounter] = new Timer(1000*messages[messageCounter].delay,messages[messageCounter]);
                            timers[messageCounter].setRepeats(false);
                            timers[messageCounter].start();                            
                            ReturnPage("Message queued successfully!");
                        }
                        break;
                    }
                    case 3:
                    {
                        ShowAdminPage();
                        break;
                    }
                }
                DisconnectFromClientSocket();
            }
            catch (Exception e)
            {
                ReturnPage(e.toString());
                e.printStackTrace();
            }
            finally
            {
                DisconnectFromClientSocket();
            }
        }
    }

    private static void OpenServerSocket() throws IOException {
       //Create socket to listen at port 3000
       webmailServerSocket = new ServerSocket(3000);
    }

    private static void ConnectToClientSocket() throws IOException {
        webmailClientSocket = webmailServerSocket.accept();
        out = new PrintWriter(webmailClientSocket.getOutputStream(),true);
        in = new BufferedReader(new InputStreamReader(webmailClientSocket.getInputStream()));
    }

    private static void DisconnectFromClientSocket() throws IOException {
        out.close();
        in.close();
        webmailClientSocket.close();
    }

    private static String[] GetHttpRequest() throws IOException {

        List <String> request = new ArrayList<String>();

        String inputLine = in.readLine();
        request.add(inputLine);

        boolean postFlag = false;
        if (inputLine.matches("^POST / HTTP/1\\..$")) { postFlag = true; }

        int contentLength = 0;

        while (!(inputLine=in.readLine()).equals(""))
        {
            if (inputLine.matches("^Content-Length: [0-9]+"))
            {
                String lengthString = inputLine.replaceAll("Content-Length: ","").trim();
                contentLength = Integer.parseInt(lengthString);
            }
            request.add(inputLine);
        }

        if (postFlag == true)
        {
            char [] buf = new char[contentLength];
            in.read(buf);
            request.add(new String(buf));
        }

        String [] httpRequest = request.toArray(new String[request.size()]);
        return httpRequest;

    }

    private static int HttpHeaderType(String[] args) throws ParseException {

        //Let's see if we have a GET request
        if (args[0].matches("^GET /(\\?)? HTTP/1\\..$"))
        {
            return 1;
        }

        //Or a POST request
        if (args[0].matches("^POST / HTTP/1\\..$"))
        {
            return 2;
        }

        //Or a request to the admin page
        if (args[0].matches("^GET /admin(\\?)? HTTP/1\\..$"))
        {
            return 3;
        }

        //Or something like GET /favicon.ico?
        if (args[0].matches("^GET /.* HTTP/1\\..$"))
        {
            return 4;
        }

        //Or something invalid
        throw new ParseException("Invalid type of request",0);
    }

    private static void ShowInputPage() throws IOException {
        out.println("HTTP/1.1 200 OK");
        out.println("Content-Type: text/html\r\n");

        BufferedReader reader = null;
        try
        {
            reader = new BufferedReader(new FileReader(new File("").getAbsolutePath()+"/src/webmail/input_form.html"));
            String inputLine = null;
            while ((inputLine=reader.readLine()) != null)
            {
                out.println(inputLine);
            }
        }
        catch (IOException ex)
        {
            System.out.println(ex.getMessage());
            ReturnPage(ex.getMessage());
        }
        finally
        {
            reader.close();
        }
    }

    public static void ReturnPage(String args) {
        out.println("HTTP/1.1 200 OK");
        out.println("Content-Type: text/html\r\n");
        out.println("<html><body>");
        //TODO: add error webpage display logic here
        String exceptionType = args.split(":")[0];
        String errorMessage = args.replaceFirst(exceptionType+": ","");
        out.println(errorMessage+"\r\n");
        out.println("<form action='' method=GET>");
        out.println("<input type=submit value='Try again'>");
        out.println("</form></body></html>");
    }

    private static void ShowAdminPage() throws Exception
    {
        out.println("HTTP/1.1 200 OK");
        out.println("Content-Type: text/html\r\n");
        out.println("<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'></head><body>");
        out.println("<h3>Pending messages</h3>");

        if (messageCounter>0)
        {
            out.println("<table border=1 border-width=1px>");
            out.println("<tr><td align=center>Sender</td>");
            out.println("<td align=center>Receiver</td>");
            out.println("<td align=center>Subject</td>");
            out.println("<td align=center>Received at</td>");
            out.println("<td align=center>Delivery at</td></tr>");

            int i = 0;

            for (i = 1; i < 30; i++)
            {
                if (messages[i]!=null)
                {
                    if (messages[i].sent == false)
                    {
                        out.println("<tr><td align=center>");
                        out.println(messages[i].senderMailAccount+"@"+messages[i].senderMailServer);

                        out.println("</td><td align=center>");
                        out.println(messages[i].receiverMailAccount+"@"+messages[i].receiverMailServer);

                        out.println("</td><td align=center>");
                        out.println(messages[i].subject);

                        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd 'at' hh:mm:ss");

                        out.println("</td><td align=center>");
                        out.println(dateFormat.format(messages[i].receivedTime.getTime()));

                        out.println("</td><td align=center>");
                        out.println(dateFormat.format(messages[i].deliveryTime.getTime()));

                        out.println("</td></tr>");
                    }
                }
            }
            out.println("</table>");
        }
        else
        {
            out.println("No pending messages right now");
        }
        out.println("<form action=/><input type=submit value='Back'>");
        out.println("</body></html>");
    }
}
